#include "Bsp.h"

volatile int32_t ITM_RxBuffer;

void BSP_SystemClock_Config(void)
{
    LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);

    if (LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2) {
        BSP_Assert(0);
    }
    
    #if RCC_HSE_Enable
        LL_RCC_HSE_Enable();
        while(LL_RCC_HSE_IsReady() != 1);   //等待HSE就绪
        LL_RCC_HSE_EnableCSS();             //开启时钟保护
        LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE_DIV_1, LL_RCC_PLL_MUL_9);  //PLL时钟 = HSE / 1 * 9 = 72MHz
    #else
        LL_RCC_HSI_SetCalibTrimming(16);    //HSI校准, 默认8MHz
        LL_RCC_HSI_Enable();                //HSI使能
        while (LL_RCC_HSI_IsReady() != 1);
        LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI_DIV_2, LL_RCC_PLL_MUL_16);  //PLL时钟 = HSI / 2 * 16 = 64MHz
    #endif  /* RCC_HSE_Enable */
    
    LL_RCC_PLL_Enable();
    while (LL_RCC_PLL_IsReady() != 1);

    LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
    LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
    LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
    LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
    while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL);
}

void BSP_SysTick_Init(uint32_t Ticks)
{
    SysTick->LOAD  = (uint32_t)(Ticks - 1UL);                   /* 设置重装值 */
    SysTick->VAL   = 0UL;                                       /* 清除计数值 */
    SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                     SysTick_CTRL_ENABLE_Msk;                   /* 启用Systick */
}

void BSP_GPIO_Init(void)
{
    LL_GPIO_InitTypeDef GPIO_InitStruct;
    LL_EXTI_InitTypeDef EXTI_InitStruct;
    
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);

#if BSP_Debug
    GPIO_InitStruct.Pin        = DEBUG_RST_PIN;  
    GPIO_InitStruct.Mode       = LL_GPIO_MODE_INPUT;
    GPIO_InitStruct.Speed      = LL_GPIO_SPEED_FREQ_MEDIUM;
    GPIO_InitStruct.Pull       = LL_GPIO_PULL_DOWN;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    LL_GPIO_Init(DEBUG_RST_PORT, &GPIO_InitStruct);
    
    // 中断
    EXTI_InitStruct.Line_0_31      = LL_EXTI_LINE_0;
    EXTI_InitStruct.LineCommand    = ENABLE;
    EXTI_InitStruct.Mode           = LL_EXTI_MODE_IT;
    EXTI_InitStruct.Trigger        = LL_EXTI_TRIGGER_RISING;
    LL_EXTI_Init(&EXTI_InitStruct);
    
    NVIC_EnableIRQ(EXTI0_IRQn);
#endif

    GPIO_InitStruct.Pin        = LL_GPIO_PIN_13|LL_GPIO_PIN_14|LL_GPIO_PIN_15;
    GPIO_InitStruct.Mode       = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed      = LL_GPIO_SPEED_FREQ_MEDIUM;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void BSP_WDT_Init(void)
{
    LL_IWDG_EnableWriteAccess(IWDG);
    LL_IWDG_SetPrescaler(IWDG, LL_IWDG_PRESCALER_64);   // 40KHz / 64
    LL_IWDG_SetReloadCounter(IWDG, 625);  // 递减, 12bit 最大0xFFF
    LL_IWDG_DisableWriteAccess(IWDG);
}

/* BSP 初始化 ===========================================================*/
void BSP_init(void)
{
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_AFIO);  //使能 IO复用时钟
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);   //使能 电源时钟

    // 调试IO使能
    LL_GPIO_AF_Remap_SWJ_NOJTAG();

    NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
    
    // 时钟初始化
    BSP_SystemClock_Config();
    SystemCoreClockUpdate();
    
    // GPIO初始化
    BSP_GPIO_Init();
    
    // WDT 初始化
    BSP_WDT_Init();
}

void BSP_Startup(void)
{
    // Systick 初始化
    BSP_SysTick_Init(SystemCoreClock / BSP_TICKS_PER_SEC);
    NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
    
    // 启动看门狗
    if ((LL_PWR_IsActiveFlag_SB() == 0) || LL_RCC_IsActiveFlag_IWDGRST() == 0)
    {
        LL_IWDG_Enable(IWDG);
    }
    else
    {
        // 设置待机标志，立即进入待机处理
    }
    
    LL_PWR_ClearFlag_SB();
    LL_PWR_ClearFlag_WU();
    LL_RCC_ClearResetFlags();
    
    // 启动Systick定时器
    Bsp_SysTick_Start();
}

void BSP_TickDelay(uint32_t Delay)
{
    __IO uint32_t  tmp = SysTick->CTRL;  /* Clear the COUNTFLAG first */

    ((void)tmp);

    while (Delay)
    {
        if ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) != 0U)
        {
            Delay--;
        }
    }
}

void BSP_usDelay(uint32_t usDelay)
{
    uint32_t delta;
 
    /* 获得延时经过的tick数 */
    usDelay = usDelay * (SysTick->LOAD / (1000000 / BSP_TICKS_PER_SEC));
 
    /* 获得当前时间 */
    delta = SysTick->VAL;
 
    /* 循环获得当前时间，直到达到指定的时间后退出循环 */
    while ((delta - SysTick->VAL) < usDelay);
}

void BSP_onAssert(char *file, uint32_t line) 
{
    #if BSP_Debug
        printf("File: %s, Line: %d\r\n", file, line);

        while (LL_GPIO_IsInputPinSet(DEBUG_RST_PORT, DEBUG_RST_PIN) == RESET);
    #endif

    // 复位MCU
    NVIC_SystemReset();
}

// DWT初始化
void BSP_DWT_Rst(void)
{
    // 启用DWT
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    
    DWT->CYCCNT = 0;
    DWT->CTRL   = DWT_CTRL_CYCCNTENA_Msk;
}

// 获取DWT计数
uint32_t BSP_DWT_Get_usTime(void)
{
    DWT->CTRL = 0;
    
    return DWT->CYCCNT / (SystemCoreClock / 1000000);
}

int fputc(int ch, FILE *f)
{
    return ITM_SendChar(ch);
}

int fgetc(FILE *f)
{
    return ITM_ReceiveChar();
}
